[fault-injection] Unprotected access to JVM class loader data mutex and method list - #779
zhengyu123 wants to merge 8 commits into
Conversation
Scan-Build Report
Bug Summary
Reports
|
||||||||||||||||||||||||||||||||||||
CI Test ResultsRun: #35372751835 | Commit:
Status Overview
Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled Summary: Total: 32 | Passed: 32 | Failed: 0 Updated: 2026-09-18 17:31:39 UTC |
❌ ErrorsYour PR has failed checks. Please review the issues below and take necessary action before merging. 🚦 4 Pipeline jobs failed
Useful? React with 👍 / 👎 This comment will be updated automatically if new data arrives.🔗 Commit SHA: 08ef73b | Docs | View more details | Give us feedback! |
…va-profiler into zgu/jdk8_patchClassLoaderData
There was a problem hiding this comment.
More details
The static review finds no defect in the JDK 8 lock recovery or per-class delta tag paths.
🤖 Datadog Autotest · Commit 2ba3f13 · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 08ef73bae8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (method_count <= already_patched) { | ||
| return -1; |
There was a problem hiding this comment.
Re-prime redefined classes on JDK 8
On JDK 8, after a class whose prior MethodList capacity was exhausted (for example, an 8-method class) is redefined or retransformed, its jclass tag and method count remain unchanged, so this branch skips the preallocation entirely. The hooks in vmEntry.cpp:671-692 explicitly reload jmethodIDs after those operations invalidate them; the subsequent GetClassMethods can therefore allocate through the original tail layout that the JDK-8062116 workaround is intended to avoid. Clear or version the recorded tag for redefinition/retransformation rather than treating an unchanged count as already primed.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
A JDK 8 class transformation keeps the old tag. The next method reload skips the required MethodList preallocation when the method count stays the same.
🤖 Datadog Autotest · Commit 08ef73b · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest
| if (jvmti == nullptr || jvmti->GetTag(klass, &already_patched) != JVMTI_ERROR_NONE) { | ||
| already_patched = 0; | ||
| } | ||
| if (method_count <= already_patched) { |
There was a problem hiding this comment.
Keep preallocation after class transformation
JDK 8 class transformations can use the slow HotSpot list path that the JDK-8062116 workaround prevents.
Assertion details
- Input: A tagged JDK 8 class completes RedefineClasses or RetransformClasses without a method-count change.
- Expected:
Class redefinition and retransformation must add fresh MethodList capacity before they reload invalid jmethodIDs. - Actual:
The old tag makes patchClassLoaderData return before it adds new MethodList capacity. GetClassMethods then reloads invalid jmethodIDs without the JDK 8 workaround.
Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest · Open Bits AI session
What does this PR do?:
Hotspot JDK8 specific.
patchClassLoaderData()prependsMethodListblocks onto a class'sClassLoaderDatato work around a JDK 8 jmethodID layout bug. This PR hardens that path:cld->lock()/methodList()mutation and its matchingcld->unlock()with the profiler's signal/crash-protection machinery (ProfiledThread,JmpCtxScope,sigsetjmp/SIGNAL_HANDLER_UNWIND_AFTER_LONGJMP), via the newLockStateRAII helper, so a crash while the classloader-data mutex is held during a signal-unsafe window unlocks it instead of deadlocking the JVM.jclass(via JVMTIGet/SetTag) with themethod_countalready prepended, so repeated calls for the same class (profiler restart replay,RedefineClasses/RetransformClasses) only prepend the delta instead of leaking another full set ofMethodListblocks on every re-run.cld->lock()suppresses safepoint checks whileGet/SetTagare safepoint-polling JVMTI entry points.Motivation:
Fault injection testing found that unprotected access to the JVM class loader data mutex and method list in
patchClassLoaderData()could crash or deadlock the JVM.Additional Notes:
The
SetTag()call is not serialized against a concurrentpatchClassLoaderData()call for the same class, so two racing callers can both observe a stale tag and both patch. This only wastes one extra round of preallocated blocks in that rare case; unlike the original unguarded code, it can no longer grow unboundedly.How to test the change?:
Added unit tests in
ddprof-lib/src/test/cpp/hotspotSupport_ut.cppcovering the locking/crash-protection and idempotent-tagging behavior ofpatchClassLoaderData().For Datadog employees:
credentials of any kind, I've requested a security review (run the
dd:platform-security-reviewskill, or file a request via the PSEC review form).
bewairealso runs automatically on every PR.Unsure? Have a question? Request a review!